/*
Copyright(C)2025. Huawei Technologies Co.,Ltd. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*
Package rescheduling is using for HuaWei Ascend pin fault rescheduling.
*/
package rescheduling

import (
	"github.com/agiledragon/gomonkey/v2"
	"k8s.io/client-go/kubernetes"
	"reflect"
	"strconv"
	"testing"
	"volcano.sh/volcano/pkg/scheduler/api"
	"volcano.sh/volcano/pkg/scheduler/framework"
	"volcano.sh/volcano/pkg/scheduler/plugins/ascend-volcano-plugin/common/util"
	"volcano.sh/volcano/pkg/scheduler/plugins/ascend-volcano-plugin/plugin"
	"volcano.sh/volcano/pkg/scheduler/plugins/ascend-volcano-plugin/test"
)

func Test_is910A5Job(t *testing.T) {
	tests := []struct {
		name string
		job  *plugin.SchedulerJob
		want bool
	}{
		{
			name: "nil job",
			job:  nil,
			want: false,
		},
		{
			name: "selector has key but not A5",
			job: &plugin.SchedulerJob{
				SchedulerJobAttr: util.SchedulerJobAttr{
					ComJob: util.ComJob{Selector: map[string]string{
						util.AcceleratorType: "910B",
					}}}},
			want: false, // 假设CheckA5Label("910B") == false
		},
		{
			name: "selector has A5",
			job: &plugin.SchedulerJob{
				SchedulerJobAttr: util.SchedulerJobAttr{
					ComJob: util.ComJob{Selector: map[string]string{
						util.AcceleratorType: "900SuperPod-A5-8",
					}}}},
			want: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := is910A5Job(tt.job); got != tt.want {
				t.Errorf("is910A5Job() = %v, want %v", got, tt.want)
			}
		})
	}
}

const (
	testTp8        = 8
	testTp4        = 4
	testTp2        = 2
	testTp1        = 1
	nodeNum        = 8
	testCreateTime = 0
)

type inTheSameTpBlockTestCase struct {
	fields  FaultJobTestField
	name    string
	tpBlock int
	wantErr [nodeNum]bool
}

func buildInTheSameTpBlockTestCases1() []inTheSameTpBlockTestCase {
	faultTask1 := fakeReSchedulerFaultTask(true, []string{"pod0", "vcjob", "node0", "job0", "0"}, testCreateTime)
	faultTask2 := fakeReSchedulerFaultTask(false, []string{"pod1", "vcjob", "node1", "job0", "1"}, testCreateTime)
	test1 := inTheSameTpBlockTestCase{
		name: "01-inTheSameTpBlock() return true when in same tp-block=16",
		fields: FaultJobTestField{
			JobName:      "job0",
			JobUID:       "vcjob/job0",
			JobNamespace: "vcjob",
			FaultTasks:   []FaultTask{faultTask1, faultTask2},
		},
		tpBlock: testTp2,
		wantErr: [nodeNum]bool{true, true, false, false, false, false, false, false},
	}
	test2 := inTheSameTpBlockTestCase{
		name: "02-inTheSameTpBlock() return true when in same tp-block=64",
		fields: FaultJobTestField{
			JobName:      "job0",
			JobUID:       "vcjob/job0",
			JobNamespace: "vcjob",
			FaultTasks:   []FaultTask{faultTask1, faultTask2},
		},
		tpBlock: testTp8,
		wantErr: [nodeNum]bool{true, true, true, true, true, true, true, true},
	}
	return []inTheSameTpBlockTestCase{
		test1, test2,
	}
}

func buildInTheSameTpBlockTestCases2() []inTheSameTpBlockTestCase {
	faultTask1 := fakeReSchedulerFaultTask(false, []string{"pod0", "vcjob", "node0", "job0", "0"}, testCreateTime)
	faultTask2 := fakeReSchedulerFaultTask(true, []string{"pod1", "vcjob", "node1", "job0", "7"}, testCreateTime)
	test1 := inTheSameTpBlockTestCase{
		name: "03-inTheSameTpBlock() return true when in same tp-block=16",
		fields: FaultJobTestField{
			JobName:      "job0",
			JobUID:       "vcjob/job0",
			JobNamespace: "vcjob",
			FaultTasks:   []FaultTask{faultTask1, faultTask2},
		},
		tpBlock: testTp2,
		wantErr: [nodeNum]bool{false, false, false, false, false, false, true, true},
	}
	test2 := inTheSameTpBlockTestCase{
		name: "04-inTheSameTpBlock() return true when in same tp-block=32",
		fields: FaultJobTestField{
			JobName:      "job0",
			JobUID:       "vcjob/job0",
			JobNamespace: "vcjob",
			FaultTasks:   []FaultTask{faultTask1, faultTask2},
		},
		tpBlock: testTp4,
		wantErr: [nodeNum]bool{false, false, false, false, true, true, true, true},
	}
	return []inTheSameTpBlockTestCase{test1, test2}
}

func buildInTheSameTpBlockTestCases3() []inTheSameTpBlockTestCase {
	faultTask1 := fakeReSchedulerFaultTask(true, []string{"pod0", "vcjob", "node0", "job0", "0"}, testCreateTime)
	faultTask2 := fakeReSchedulerFaultTask(true, []string{"pod1", "vcjob", "node1", "job0", "7"}, testCreateTime)
	test1 := inTheSameTpBlockTestCase{
		name: "05-inTheSameTpBlock() return false when in same tp-block=8 and two fault tasks",
		fields: FaultJobTestField{
			JobName:      "job0",
			JobUID:       "vcjob/job0",
			JobNamespace: "vcjob",
			FaultTasks:   []FaultTask{faultTask1, faultTask2},
		},
		tpBlock: testTp1,
		wantErr: [nodeNum]bool{false, false, false, false, false, false, false, false},
	}
	test2 := inTheSameTpBlockTestCase{
		name: "06-inTheSameTpBlock() return true when in same tp-block=16 and two fault tasks",
		fields: FaultJobTestField{
			JobName:      "job0",
			JobUID:       "vcjob/job0",
			JobNamespace: "vcjob",
			FaultTasks:   []FaultTask{faultTask1, faultTask2},
		},
		tpBlock: testTp2,
		wantErr: [nodeNum]bool{true, true, false, false, false, false, true, true},
	}
	return []inTheSameTpBlockTestCase{test1, test2}
}

func buildInTheSameTpBlockTestCases() []inTheSameTpBlockTestCase {
	result := make([]inTheSameTpBlockTestCase, 0)
	result = append(result, buildInTheSameTpBlockTestCases1()...)
	result = append(result, buildInTheSameTpBlockTestCases2()...)
	result = append(result, buildInTheSameTpBlockTestCases3()...)
	return result
}

func testCaseRunDetail(t *testing.T, tc inTheSameTpBlockTestCase) {
	fJob := &FaultJob{
		ReScheduleKey: tc.fields.ReScheduleKey,
		IsFaultJob:    tc.fields.IsFaultJob,
		JobName:       tc.fields.JobName,
		JobUID:        tc.fields.JobUID,
		JobNamespace:  tc.fields.JobNamespace,
		FaultTasks:    tc.fields.FaultTasks,
		FaultJobA5Field: FaultJobA5Field{
			TpBlock: tc.tpBlock,
		},
	}
	for i := 0; i < nodeNum; i++ {
		if ret := fJob.inTheSameTpBlock(
			FaultTask{IsFaultTask: false, NodeRankIndex: strconv.Itoa(i)}); ret != tc.wantErr[i] {
			t.Errorf("inTheSameTpBlock() when nodeRank=%d, return = %v, but want %v", i, ret, tc.wantErr[i])
		}
	}
}

// TestInTheSameTpBlock test for the same tp-block by rankIndex
func TestInTheSameTpBlock(t *testing.T) {
	tests := buildInTheSameTpBlockTestCases()
	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			testCaseRunDetail(t, tc)
		})
	}
}

type inTheSameVSuperPodTestCase struct {
	name                     string
	TpBlock                  int
	WhetherBackToVspSchedule bool
	SuperPods                map[string][]plugin.SuperNode
	ids                      []string
	nodeName                 string
	want                     bool
}

func buildTestCase0() inTheSameVSuperPodTestCase {
	return inTheSameVSuperPodTestCase{
		name:                     "00-test The precondition failed",
		TpBlock:                  testTp2,
		WhetherBackToVspSchedule: false,
		ids:                      []string{},
		nodeName:                 "",
		want:                     false,
	}
}

func buildTestCase1() inTheSameVSuperPodTestCase {
	return inTheSameVSuperPodTestCase{
		name:                     "01-test ids don't exist",
		TpBlock:                  testTp1,
		WhetherBackToVspSchedule: true,
		SuperPods: map[string][]plugin.SuperNode{
			"0": {
				{Name: "work1"},
				{Name: "work2"},
				{Name: "work3"},
				{Name: "work4"},
				{Name: "work5"},
			},
		},
		ids:      []string{"1"},
		nodeName: "work1",
		want:     false,
	}
}

func buildTestCase2() inTheSameVSuperPodTestCase {
	return inTheSameVSuperPodTestCase{
		name:                     "02-test nodeName don't exist",
		TpBlock:                  testTp1,
		WhetherBackToVspSchedule: true,
		SuperPods: map[string][]plugin.SuperNode{
			"0": {
				{Name: "work1"},
				{Name: "work2"},
				{Name: "work3"},
				{Name: "work4"},
				{Name: "work5"},
			},
			"1": {
				{Name: "work1"},
				{Name: "work2"},
				{Name: "work3"},
				{Name: "work4"},
				{Name: "work5"},
			},
		},
		ids:      []string{"0"},
		nodeName: "work9",
		want:     false,
	}
}

func buildInTheSameVSuperPodTestCases() []inTheSameVSuperPodTestCase {
	return []inTheSameVSuperPodTestCase{
		buildTestCase0(),
		buildTestCase1(),
		buildTestCase2(),
	}
}

func TestInTheSameVSuperPod(t *testing.T) {
	for _, tc := range buildInTheSameVSuperPodTestCases() {
		fJob := &FaultJob{
			FaultJobA5Field: FaultJobA5Field{
				TpBlock:                  tc.TpBlock,
				WhetherBackToVspSchedule: tc.WhetherBackToVspSchedule},
		}
		t.Run(tc.name, func(t *testing.T) {
			if ret := fJob.inTheSameVSuperPod(tc.ids, tc.nodeName); ret != tc.want {
				t.Errorf("inTheSameVSuperPod() when ids=%v nodeName=%v, return = %v, but want %v",
					tc.ids, tc.nodeName, ret, tc.want)
			}
		})
	}
}

func checkVSuperPodIds(t *testing.T, got, want []string) {
	if len(got) != len(want) {
		t.Errorf("getVSuperPodIds() = %v, want %v", got, want)
		return
	}
	for i := range got {
		if got[i] != want[i] {
			t.Errorf("getVSuperPodIds() = %v, want %v", got, want)
			return
		}
	}
}

func TestGetVSuperPodIds(t *testing.T) {
	tests := []struct {
		name      string
		faultJobs []FaultTask
		superPods map[string][]plugin.SuperNode
		want      []string
	}{
		{
			name:      "fault task with no superpod id",
			faultJobs: []FaultTask{{IsFaultTask: true, NodeName: "node1"}},
			superPods: map[string][]plugin.SuperNode{"vsp1": {{Name: "node2"}}},
			want:      []string{},
		},
		{
			name: "multiple fault tasks, some with superpod id",
			faultJobs: []FaultTask{
				{IsFaultTask: true, NodeName: "node1"},
				{IsFaultTask: true, NodeName: "node2"},
				{IsFaultTask: false, NodeName: "node3"},
			},
			superPods: map[string][]plugin.SuperNode{
				"vsp1": {{Name: "node1"}},
				"vsp2": {{Name: "node2"}},
			},
			want: []string{"vsp1", "vsp2"},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			fJob := &FaultJob{
				FaultTasks: tt.faultJobs,
				SuperPods:  tt.superPods,
			}
			got := fJob.getVSuperPodIds()
			checkVSuperPodIds(t, got, tt.want)
		})
	}
}

type JudgeJobIsMasterFaultTest struct {
	name                     string
	FaultTasks               []FaultTask
	PendingSessionNum        int
	TpBlock                  int
	SuperPods                map[string][]plugin.SuperNode
	IsMasterFault            bool
	WhetherBackToVspSchedule bool
	vSuperPodIds             []string
	schedulerJob             *plugin.SchedulerJob
	want                     bool
}

func buildJudgeJobIsMasterFaultTestCase1() JudgeJobIsMasterFaultTest {
	return JudgeJobIsMasterFaultTest{
		name: "master-0 pod is fault, should set IsMasterFault true",
		FaultTasks: []FaultTask{
			{IsFaultTask: true, NodeRankIndex: "0"},
		},
		vSuperPodIds: []string{},
		schedulerJob: &plugin.SchedulerJob{},
		want:         true,
	}
}
func buildJudgeJobIsMasterFaultTestCase2() JudgeJobIsMasterFaultTest {
	return JudgeJobIsMasterFaultTest{
		name: "process rescheduling, master-0 in same tp block, should set IsMasterFault true",
		FaultTasks: []FaultTask{
			{IsFaultTask: false, NodeRankIndex: "0"},
			{IsFaultTask: true, NodeRankIndex: "1"},
		},
		TpBlock:      2,
		vSuperPodIds: []string{},
		schedulerJob: &plugin.SchedulerJob{
			SchedulerJobAttr: util.SchedulerJobAttr{
				ComJob: util.ComJob{
					Label: map[string]string{
						util.ProcessRecoverEnable: util.EnableFunc,
					},
				},
			},
		},
		want: true,
	}
}
func buildJudgeJobIsMasterFaultTestCase3() JudgeJobIsMasterFaultTest {
	return JudgeJobIsMasterFaultTest{
		name: "pendingSessionNum >= spPendingTimes, master-0 in same tp block, should set IsMasterFault true",
		FaultTasks: []FaultTask{
			{IsFaultTask: false, NodeRankIndex: "0"},
			{IsFaultTask: true, NodeRankIndex: "1"},
		},
		PendingSessionNum: spPendingTimes,
		TpBlock:           2,
		vSuperPodIds:      []string{},
		schedulerJob:      &plugin.SchedulerJob{},
		want:              true,
	}
}
func buildJudgeJobIsMasterFaultTestCase4() JudgeJobIsMasterFaultTest {
	return JudgeJobIsMasterFaultTest{
		name: "pendingSessionNum >= spPendingTimes, master-0 in same vsuperpod, should set IsMasterFault true",
		FaultTasks: []FaultTask{
			{IsFaultTask: false, NodeRankIndex: "0", NodeName: "node1"},
		},
		PendingSessionNum: spPendingTimes,
		SuperPods: map[string][]plugin.SuperNode{
			"vsp1": {{Name: "node1"}},
		},
		WhetherBackToVspSchedule: true,
		vSuperPodIds:             []string{"vsp1"},
		schedulerJob:             &plugin.SchedulerJob{},
		want:                     true,
	}
}
func buildJudgeJobIsMasterFaultTestCase5() JudgeJobIsMasterFaultTest {
	return JudgeJobIsMasterFaultTest{
		name: "no master fault, should set IsMasterFault false",
		FaultTasks: []FaultTask{
			{IsFaultTask: false, NodeRankIndex: "1"},
		},
		vSuperPodIds: []string{},
		schedulerJob: &plugin.SchedulerJob{},
		want:         false,
	}
}

func TestJudgeJobIsMasterFault(t *testing.T) {
	tests := []JudgeJobIsMasterFaultTest{
		buildJudgeJobIsMasterFaultTestCase1(),
		buildJudgeJobIsMasterFaultTestCase2(),
		buildJudgeJobIsMasterFaultTestCase3(),
		buildJudgeJobIsMasterFaultTestCase4(),
		buildJudgeJobIsMasterFaultTestCase5(),
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			fJob := &FaultJob{
				FaultTasks:        tt.FaultTasks,
				PendingSessionNum: tt.PendingSessionNum,
				SuperPods:         tt.SuperPods,
				FaultJobA5Field: FaultJobA5Field{
					TpBlock:                  tt.TpBlock,
					IsMasterFault:            false,
					WhetherBackToVspSchedule: tt.WhetherBackToVspSchedule,
				},
			}
			fJob.judgeJobIsMasterFault(tt.vSuperPodIds, tt.schedulerJob)
			if fJob.IsMasterFault != tt.want {
				t.Errorf("IsMasterFault = %v, want %v", fJob.IsMasterFault, tt.want)
			}
		})
	}
}

func TestGraceDeleteJobFor910A5(t *testing.T) {
	fJob := &FaultJob{JobUID: mockJobUID}
	env := plugin.ScheduleEnv{}
	env.SuperPodInfo = plugin.NewSuperPodInfo()
	npuJob := &plugin.SchedulerJob{}
	t.Run("01-GraceDeleteJobFor910A5 return error when ssn is nil", func(t *testing.T) {
		err := fJob.GraceDeleteJobFor910A5(nil, &plugin.SchedulerJob{}, env)
		if err == nil {
			t.Errorf("GraceDeleteJob() err = %v, wantErr is not nil", err)
		}
	})
	t.Run("02-GraceDeleteJobFor910A5 return error when npuJob is nil", func(t *testing.T) {
		err := fJob.GraceDeleteJobFor910A5(&framework.Session{}, nil, env)
		if err == nil {
			t.Errorf("GraceDeleteJob() err = %v, wantErr is not nil", err)
		}
	})
	t.Run("03-GraceDeleteJobFor910A5 return nil when ssn and npuJob are not nil", func(t *testing.T) {
		npuJob.Annotation = map[string]string{util.SuperPodAnnoKey: ""}
		err := fJob.GraceDeleteJobFor910A5(&framework.Session{}, npuJob, env)
		if err != nil {
			t.Errorf("GraceDeleteJob() err = %v, wantErr is nil", err)
		}
	})
}

func buildFaultJobForceDeleteJobFor910A5Tests() []FaultJobForceDeleteJobTests {
	var tmpPatch *gomonkey.Patches = nil
	faultTask1 := fakeReSchedulerFaultTask(true, []string{"pod0", "vcjob", "node0", "job0", "0"}, 0)
	faultTask2 := fakeReSchedulerFaultTask(false, []string{"pod1", "vcjob", "node1", "job0", "1"}, 0)
	schedulerJob := fakeSchedulerJobEmptyTask("job0", "vcjob")
	test1 := FaultJobForceDeleteJobTests{
		name: "01-FaultJobForceDeleteJob()-delete success",
		fields: FaultJobTestField{
			JobName:             "job0",
			JobUID:              "vcjob/job0",
			JobNamespace:        "vcjob",
			JobRankIds:          nil,
			NodeNames:           nil,
			FaultTasks:          []FaultTask{faultTask1, faultTask2},
			UpdateTime:          0,
			JobRankIdCreateTime: 0,
			FaultTypes:          nil,
			DeleteExecutedFlag:  false,
		},
		args: FaultJobForceDeleteJobArgs{
			schedulerJob: &schedulerJob,
			cacheFuncBefore: func() {
				tmpPatch = gomonkey.ApplyMethod(reflect.TypeOf(&FaultTask{}), "DeleteRealPodByTask",
					func(_ *FaultTask, _ kubernetes.Interface, _ int64) error { return nil })
			},
			cacheFuncAfter: func() {
				if tmpPatch != nil {
					tmpPatch.Reset()
				}
			},
		},
		wantErr: false,
	}
	tests := []FaultJobForceDeleteJobTests{
		test1,
	}
	return tests
}

// TestFaultJobForceDeleteJob test for force delete function
func TestFaultJobForceDeleteJobFor910A5(t *testing.T) {
	env := plugin.ScheduleEnv{}
	env.SuperPodInfo = plugin.NewSuperPodInfo()
	tests := buildFaultJobForceDeleteJobFor910A5Tests()
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tt.args.cacheFuncBefore()
			fJob := &FaultJob{
				ReScheduleKey:      tt.fields.ReScheduleKey,
				IsFaultJob:         tt.fields.IsFaultJob,
				JobName:            tt.fields.JobName,
				JobUID:             tt.fields.JobUID,
				JobNamespace:       tt.fields.JobNamespace,
				FaultTasks:         tt.fields.FaultTasks,
				UpdateTime:         tt.fields.UpdateTime,
				FaultTypes:         tt.fields.FaultTypes,
				DeleteExecutedFlag: tt.fields.DeleteExecutedFlag,
				ElasticScheduling:  tt.fields.ElasticScheduling,
			}
			if err := fJob.ForceDeleteJobFor910A5(tt.args.schedulerJob, env); (err != nil) != tt.wantErr {
				t.Errorf("ForceDeleteJobFor910A5() error = %v, wantErr %v", err, tt.wantErr)
			}
			tt.args.cacheFuncAfter()
		})
	}
}

type skipThisTaskTestCase struct {
	name            string
	fJob            *FaultJob
	cacheFuncBefore func()
	cacheFuncAfter  func()
	schedulerJob    *plugin.SchedulerJob
	dpi             *deletePodInfo
	fTask           FaultTask
	want            bool
}

func buildSkipThisTaskTestCase1() skipThisTaskTestCase {
	var tmpPatch *gomonkey.Patches = nil
	schedulerJob := &plugin.SchedulerJob{}
	schedulerJob.Label = map[string]string{
		util.ProcessRecoverEnable: util.EnableFunc,
	}
	return skipThisTaskTestCase{
		name: "01-SkipThisTask return false when in the same tp block",
		fJob: &FaultJob{},
		cacheFuncBefore: func() {
			tmpPatch = gomonkey.ApplyPrivateMethod(reflect.TypeOf(&FaultJob{}), "inTheSameTpBlock",
				func(fTask FaultTask) bool { return true })
		},
		cacheFuncAfter: func() {
			if tmpPatch != nil {
				tmpPatch.Reset()
			}
		},
		dpi: &deletePodInfo{
			isSuperPod:    true,
			isMasterFault: false,
		},
		fTask: FaultTask{
			IsFaultTask: false,
		},
		schedulerJob: schedulerJob,
		want:         false,
	}
}

func buildSkipThisTaskTestCase2() skipThisTaskTestCase {
	var tmpPatch *gomonkey.Patches = nil
	schedulerJob := &plugin.SchedulerJob{}
	schedulerJob.Label = map[string]string{
		util.ProcessRecoverEnable: util.ProcessRecoverPause,
	}
	return skipThisTaskTestCase{
		name: "01-SkipThisTask return false when process rescheduling failed",
		fJob: &FaultJob{},
		cacheFuncBefore: func() {
			tmpPatch = gomonkey.ApplyPrivateMethod(reflect.TypeOf(&FaultJob{}), "inTheSameTpBlock",
				func(fTask FaultTask) bool { return true })
		},
		cacheFuncAfter: func() {
			if tmpPatch != nil {
				tmpPatch.Reset()
			}
		},
		dpi: &deletePodInfo{
			isSuperPod:    true,
			isMasterFault: false,
		},
		fTask: FaultTask{
			IsFaultTask: false,
		},
		schedulerJob: schedulerJob,
		want:         false,
	}
}

func buildSkipThisTaskTestCase3() skipThisTaskTestCase {
	var tmpPatch *gomonkey.Patches = nil
	fJob := &FaultJob{}
	fJob.PendingSessionNum = 7
	fJob.WhetherBackToVspSchedule = true
	schedulerJob := &plugin.SchedulerJob{}
	schedulerJob.Label = map[string]string{
		util.SinglePodTag: util.EnableFunc,
	}
	return skipThisTaskTestCase{
		name: "01-SkipThisTask return false when process in the same VSuperPod",
		fJob: fJob,
		cacheFuncBefore: func() {
			tmpPatch = gomonkey.ApplyPrivateMethod(reflect.TypeOf(&FaultJob{}), "inTheSameVSuperPod",
				func(fTask FaultTask) bool { return true })
		},
		cacheFuncAfter: func() {
			if tmpPatch != nil {
				tmpPatch.Reset()
			}
		},
		dpi: &deletePodInfo{
			isSuperPod:    true,
			isMasterFault: false,
		},
		fTask: FaultTask{
			IsFaultTask: false,
		},
		schedulerJob: schedulerJob,
		want:         false,
	}
}

func buildSkipThisTaskTestCases() []skipThisTaskTestCase {
	return []skipThisTaskTestCase{
		buildSkipThisTaskTestCase1(),
		buildSkipThisTaskTestCase2(),
		buildSkipThisTaskTestCase3(),
	}
}

func TestSkipThisTask(t *testing.T) {
	testCases := buildSkipThisTaskTestCases()
	for _, tt := range testCases {
		t.Run(tt.name, func(t *testing.T) {
			tt.cacheFuncBefore()
			if res := tt.fJob.skipThisTask(tt.dpi, tt.fTask, tt.schedulerJob); res != tt.want {
				t.Errorf("skipThisTask() res = %v, want is %v", res, tt.want)
			}
			tt.cacheFuncAfter()
		})
	}
}

func TestGraceDeletePodsFor910A5(t *testing.T) {
	fJob := mockFaultJobWithTasks()
	ssn := test.FakeNormalSSN(nil)
	npuJob := &plugin.SchedulerJob{
		SchedulerJobAttr: util.SchedulerJobAttr{
			NPUJob: &util.NPUJob{
				Tasks: map[api.TaskID]util.NPUTask{},
			},
		},
	}
	env := plugin.ScheduleEnv{}
	env.SuperPodInfo = plugin.NewSuperPodInfo()
	t.Run("01-graceDeletePodsFor910A5 do not change IsBeingGracefulDeleted when npuTask not in session",
		func(t *testing.T) {
			var tmpPatch *gomonkey.Patches = nil
			tmpPatch = gomonkey.ApplyPrivateMethod(reflect.TypeOf(&util.NPUTask{}), "ForceDeletePodByTaskInf",
				func(ssn *framework.Session, reason string, nodeName string) error { return nil })
			fJob.graceDeletePodsFor910A5(ssn, npuJob, env, &deletePodInfo{})
			tmpPatch.Reset()
			for id := range fJob.FaultTasks {
				if fJob.FaultTasks[id].IsBeingGracefulDeleted == true {
					t.Error("graceDeletePodsFor910A5() return true, want false")
				}
			}
		})
	t.Run("02-graceDeletePodsFor910A5 change IsBeingGracefulDeleted when npuTask in session", func(t *testing.T) {
		npuJob.Label = map[string]string{}
		npuJob.Tasks = map[api.TaskID]util.NPUTask{mockTaskUID: {
			VTask: &util.VTask{Allocated: util.TaskAllocated{}}}}
		var tmpPatch *gomonkey.Patches = nil
		tmpPatch = gomonkey.ApplyPrivateMethod(reflect.TypeOf(&util.NPUTask{}), "ForceDeletePodByTaskInf",
			func(ssn *framework.Session, reason string, nodeName string) error { return nil })
		fJob.graceDeletePodsFor910A5(ssn, npuJob, env, &deletePodInfo{})
		tmpPatch.Reset()
		for id := range fJob.FaultTasks {
			if fJob.FaultTasks[id].IsBeingGracefulDeleted == false {
				t.Error("graceDeletePodsFor910A5() return false, want true")
			}
		}
	})
}
